/**
 * Copyright (c) 2010-2011 julewa.com.  
 * All rights reserved. 
 * 
 * @author Huang Benhua
 * @date 2011-2-20
 * 
**/
package com.julewa.loading;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Enumeration;

import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

public final class ContextProxyUtils {
	
	private static abstract class LocalProxy implements InvocationHandler{
		protected Object object;
		protected String values[];
		public LocalProxy(Object obj, String ... strings){
			object = obj;
			values = strings;
		}
		@SuppressWarnings("unchecked")
		public <T> T createProxy(Class<T> c){
			return (T) Proxy.newProxyInstance(
					c.getClassLoader(), 
					new Class[]{c},
					this);
		}
		public abstract Object invoke(Method m, Object[] args) throws Throwable ;

		@SuppressWarnings("rawtypes")
		public Object invoke(Object o, Method m, Object[] args) throws Throwable {
			if(m.getName().equals(values[0])){
				return invoke(m, args);
			}
			if(m.getName().equals("getInitParameterNames")){
				Enumeration enm = (Enumeration)m.invoke(object, args);
				enm = (new Enumeration(){
					//Enumeration e;
					String k = null;
					Enumeration init(Enumeration enm, String key){
						//e = enm;
						k = key;
						return this;
					}
					public boolean hasMoreElements() {
						//return e.hasMoreElements() && k != null;
						return k != null;
					}
					public Object nextElement() {
						//if(e.hasMoreElements())return e.nextElement();
						if(k == null) return null;
						String kk = k;
						k = null;
						return kk;
					}
				}).init(enm, values[1]);
				return enm;
			}
			return m.invoke(object, args);
		}
	}
	
	private static LocalProxy getConfigProxy(Object obj, String key, String value){
		return new LocalProxy(obj, "getInitParameter", key, value){
			@Override
			public Object invoke(Method m, Object[] args) throws Throwable {
				String k = (String)args[0];
				if(values[1].equals(k)){
					return values[2];
				}
				return m.invoke(object, args); 
			}
		};
	}
	
	static ServletContext getProxy(ServletContext ctx, String key, String value){
		return getConfigProxy(ctx, key, value).createProxy(ServletContext.class);
	}
	
	static FilterConfig getProxy(FilterConfig conf, String path){
		return getConfigProxy(conf, "config", path).createProxy(FilterConfig.class);
	}
	
	public static ServletResponse getProxy(ServletResponse resp){
		return (new LocalProxy(resp){
			public Object invoke(Method m, Object[] args) throws Throwable {
				return null;
			}
			public Object invoke(Object o, Method m, Object[] args) throws Throwable {
				if("setContentType".equals(m.getName())){
					return null;
				}
				return m.invoke(object, args);
			}
			
		}).createProxy(HttpServletResponse.class);
	}
	
}
